`include "../../include/cpu_defines.sv"

module MemIssueQueue
#(parameter BUFFER_SIZE=8,
parameter STORE_BUFFER_SIZE=4,
parameter BUFFER_WIDTH=$clog2(BUFFER_SIZE),
parameter STORE_BUFFER_WIDTH=$clog2(STORE_BUFFER_SIZE))(
	input logic cpu_clk,
	input logic cpu_rst_n,
	input logic clear,
	input logic cp0_clear,
	input logic branch_fail_clear,
	input logic stall,
	input logic en1,
	input logic en2,
	input logic [5: 0] inst1_rs,
	input logic [5: 0] inst2_rs,
	input logic [5: 0] inst1_rt,
	input logic [5: 0] inst2_rt,
	input logic [5: 0] inst1_rd,
	input logic [5: 0] inst2_rd,
	input logic [`EXC_CODE_BUS] inst1_exccode,
	input logic [`EXC_CODE_BUS] inst2_exccode,
	input logic [`MEMOP_BUS] inst1_memop,
	input logic [`MEMOP_BUS] inst2_memop,
	input logic inst1_rs_ready,
	input logic inst1_rt_ready,
	input logic inst2_rs_ready,
	input logic inst2_rt_ready,
	input logic [31: 0] inst1_src2,
	input logic [31: 0] inst2_src2,
	input logic [5: 0] rob_index1,
	input logic [5: 0] rob_index2,
	input logic retire_en1,
	input logic retire_en2,
	input logic retire_ll1,
	input logic retire_ll2,
	input logic [5: 0] retire_rob_index1,
	input logic [5: 0] retire_rob_index2,
	input logic wb_en1,
	input logic wb_en2,
	input logic wb_en3,
	input logic [5: 0] wb_rd1,
	input logic [5: 0] wb_rd2,
	input logic [5: 0] wb_rd3,
	input logic inst_wb_receive,

	output logic [5: 0] search1,
	output logic [5: 0] search2,
	output logic [5: 0] search3,
	output logic search4_en,
	output logic [5: 0] search4, // search port share with cp0 issue queue, for lwl, lwr
	input logic [31: 0] data1,
	input logic [31: 0] data2,
	input logic [31: 0] data3,
	input logic [31: 0] data4,

	output logic mem_end,
	output logic [5: 0] mem_rd,
	output logic [5: 0] next_mem_rd,
	output logic [5: 0] mem_rob_index,
	output logic [31: 0] mem_data,
	(* mark_debug="true" *)
	output logic [31: 0] mem_addr,
	output logic dis_mem_stall_req,
	output logic [`EXC_CODE_BUS] mem_exccode,
	output logic vaddr_we,
	output logic entryhi_we,

	input logic data_addr_ok,
	input logic data_data_ok,
	input logic data_waddr_ok,
	input logic data_wuncache_ok,
	input logic write_accept,
	input logic data_success,
	input logic enable_miss_back,
	input logic [31: 0] data_rdata,
	input logic [2: 0] read_queue_index,
	input logic mshr_data_ok,
	input logic [2: 0] mshr_queue_index,
	input logic [31: 0] mshr_data,
	input logic rdata_tlb_invalid,
	input logic rdata_tlb_refill,
	input logic wdata_tlb_invalid,
	input logic wdata_tlb_refill,
	input logic data_tlb_modify,
	output logic [19: 0] vwtag,
	input logic [19: 0] pwtag,
	input logic data_uncache,
	(* mark_debug="true" *)
	output logic data_req,
	output logic data_abandon_lookup,
	output logic data_clear,
	(* mark_debug="true" *)
	output logic data_write_req,
	output logic enable_miss,
	output logic [$clog2(BUFFER_SIZE)-1: 0] out_queue_index,
	output logic [3: 0] data_rwstrb,
	output logic [3: 0] data_wstrb,
	(* mark_debug="true" *)
	output logic [31: 0] data_addr,
	(* mark_debug="true" *)
	output logic [31: 0] data_waddr,
	(* mark_debug="true" *)
	output logic [31: 0] data_wdata,
	output logic [19: 0] data_write_ptag,
	output logic wdata_uncache
);

	typedef struct packed{
		// logic en;
		// logic rs_ready;
		logic data_ready;
		logic force_search;
		// logic in_reorder;
		// logic reorderable;
		logic tlb_refill;
		logic tlb_invalid;
		logic is_unsigned;
		logic lwl, lwr;
		// logic direction;
		logic [`EXC_CODE_BUS] exccode;
		logic [1: 0] size;
		logic [$clog2(BUFFER_SIZE): 0] index;
		logic [5: 0] rs, rt, rd;
		logic [5: 0] rob_index;
		logic [31: 0] offset;
		logic [31: 0] addr;
		logic [31: 0] data;
		logic [31: 0] rt_data;
	}ReadBuffer_t;

	typedef struct packed { 
		logic rs_ready, rt_ready, wb_ready, in_store, swl, swr, sc, llbit;
		logic tlb_refill, tlb_invalid, tlb_modify;
		logic [`EXC_CODE_BUS] exccode;
		logic [1: 0] size;
		logic [$clog2(STORE_BUFFER_SIZE)-1: 0] store_index;
		logic [$clog2(BUFFER_SIZE)-1: 0] wp_index;
		logic [5: 0] rs, rt, rd;
		logic [5: 0] rob_index;
		logic [31: 0] offset;
		logic [31: 0] addr;
		logic [3: 0] store_wstrb;
		logic [31: 0] store_data;
	} WriteBuffer_t;

	typedef struct packed{
		logic [$clog2(BUFFER_SIZE)-1: 0] index;
		logic [29: 0] addr;
		logic [31: 0] data;
		logic [3: 0] wstrb;
	} StoreBuffer_t;
	typedef enum { READ_IDLE, READ_BUSY } read_state_t;

	ReadBuffer_t read_buffer[BUFFER_SIZE-1: 0];
	WriteBuffer_t write_buffer[BUFFER_SIZE-1: 0];
	StoreBuffer_t store_buffer[STORE_BUFFER_SIZE-1: 0];
	StoreBuffer_t store_backup_buffer[STORE_BUFFER_SIZE-1: 0];
	read_state_t read_state;
	logic [BUFFER_SIZE-1: 0] read_en;
	logic [BUFFER_SIZE-1: 0] write_en, write_en_mask;
	logic [BUFFER_SIZE-1: 0] read_rs_ready, read_rt_ready;
	logic [BUFFER_SIZE-1: 0] in_reorder, reorderable;
	logic [BUFFER_SIZE-1: 0] read_direction, write_direction;
	logic [STORE_BUFFER_SIZE-1: 0] store_buffer_en, store_buffer_en_mask, store_backup_en, next_store_backup_en, store_backup_en_mask;
	logic [BUFFER_SIZE-1: 0][$clog2(BUFFER_SIZE): 0] write_index;
	logic state_read_idle, state_read_busy;
	logic llbit, retire_llbit;

	logic ena, enb, wea, wp_full;
	logic [88: 0] dina, douta, doutb;
	logic [$clog2(BUFFER_SIZE)-1: 0] addra, addrb;
	logic [31: 0] write_store_data;
	logic on_exception;
	logic [`EXC_CODE_BUS] out_exccode;
	logic rd_abandon;
	logic [$clog2(BUFFER_SIZE)-1: 0] abandon_index;
	logic [2: 0] wp_head, wp_tail, wp_retire_tail, wp_retire_tailp1, wp_clear_head, wp_retire_clear_tail;
	logic [7: 0] write_placehold_en, write_placehold_en_mask;

	assign write_placehold_en_mask = (((9'b1 << wp_retire_clear_tail) - 1) ^ ((9'b1 << wp_clear_head) - 1));
	assign wp_full = wp_head == wp_tail && write_placehold_en[wp_head];
	SDPRAM #(
		.WORD_WIDTH(89),
		.DEPTH(BUFFER_SIZE),
		.ADDR_WIDTH($clog2(BUFFER_SIZE))
	) write_placehold_buffer(
		.clk(cpu_clk),
		.ena(ena),
		.addra(addra),
		.wea(wea),
		.dina(dina),
		.douta(douta),
		.enb(enb),
		.addrb(addrb),
		.doutb(doutb)
	);

	logic [35: 0] snap_outa, snap_outb;
	logic [STORE_BUFFER_SIZE-1: 0] wr_conflict, read_conflict, read_relavant;
	logic [$clog2(STORE_BUFFER_SIZE)-1: 0] store_index, conflict_index;
	logic [$clog2(BUFFER_SIZE)-1: 0] addr_read_index;
	logic addr_read_ready;
	logic tail_read, read_searching, searching_conflict, searching_relavant;
	logic [3: 0] searching_wstrb;
	SDPRAM #(
		.WORD_WIDTH(36), 
		.DEPTH(BUFFER_SIZE),
		.ADDR_WIDTH($clog2(BUFFER_SIZE))
	) read_snap_buffer(
		.clk(cpu_clk),
		.ena(1'b1),
		.addra(addr_read_index),
		.wea(read_searching),
		.dina(({36{|read_relavant}} & {store_buffer[conflict_index].data, store_buffer[conflict_index].wstrb})),
		.douta(snap_outa),
		.enb(data_data_ok),
		.addrb(read_queue_index),
		.doutb(snap_outb)
	);

	logic write_ready, pre_write_ready, pre_addr_ok, write_ok;
	logic writeable, write_lock, need_write, swl, swr;
	logic wr_addr_conflict, store_valid, read_tail_ready;
	logic is_read_tail, is_write_tail, is_write_tail_next;
	logic requestor;
	logic next_clear;
	logic read_exception, read_uncache, write_uncache, store_uncache;
	logic [`EXC_CODE_BUS] read_exccode, write_exccode, write_out_exccode, read_out_exccode;
	logic [BUFFER_SIZE-1: 0] tail_reorderable;
	logic [31: 0] write_addr, store_combine_data, read_addr, store_read_addr, write_data, store_data3;
	logic [31: 0] read_offset, prf_write_addr;
	logic [1: 0] write_addr_offset, read_addr_offset;
	logic [1: 0] read_add_num, index_add_num, write_add_num, write_size, retire_num;
	logic [3: 0] write_wstrb, read_wstrb, store_read_wstrb;
	logic [BUFFER_SIZE-1: 0] read_ready;
	logic [31: 0] read_combine_data, read_out_data;
	logic [$clog2(BUFFER_SIZE): 0] current_index, read_remain_count, write_remain_count, current_indexp1,clear_retire_tail, clear_remain_count;
	logic [$clog2(BUFFER_SIZE)-1: 0] read_head, read_tail, write_head, write_tail, write_search_tail, write_wb_tail, write_retire_tail, clear_write_tail, read_search_tail;
	logic [$clog2(BUFFER_SIZE)-1: 0] write_tailp1, read_headp1, write_retirep1, read_index, read_index_encode;
	logic [$clog2(BUFFER_SIZE)-1: 0] read_indexp1, write_indexp1, pre_search_tail, write_tail_next;
	logic [$clog2(STORE_BUFFER_SIZE)-1: 0] store_free_index;
	logic direction, directionp1;

	logic inst1_store, inst1_load, inst2_store, inst2_load, inst1_retire, inst2_retire;

	logic store1, load1, store2, load2, inst1_unsigned, inst2_unsigned;
	logic [1: 0] inst1_memsize, inst2_memsize;

	assign store1 = inst1_memop[4];
	assign store2 = inst2_memop[4];
	assign load1 = ~inst1_memop[4];
	assign load2 = ~inst2_memop[4];
	assign inst1_unsigned = ~inst1_memop[4] & ~inst1_memop[3] & inst1_memop[2];
	assign inst2_unsigned = ~inst2_memop[4] & ~inst2_memop[3] & inst2_memop[2];
	assign inst1_memsize = inst1_memop[1: 0];
	assign inst2_memsize = inst2_memop[1: 0];

	assign dis_mem_stall_req = read_remain_count < read_add_num || write_remain_count < write_add_num;
	assign search1 = write_buffer[write_search_tail].rs;
	assign search2 = write_buffer[write_search_tail].rt;
	assign search3 = read_buffer[read_index].rs;
	assign search4_en = read_searching & (read_buffer[addr_read_index].lwl | read_buffer[addr_read_index].lwr);
	assign search4 = read_buffer[addr_read_index].rt;

	assign data_write_req = write_placehold_en[wp_head] & (~wdata_uncache | wdata_uncache & data_wuncache_ok);
	assign data_wstrb = doutb[67: 64];
	assign data_waddr = doutb[63: 32];
	assign data_wdata = doutb[31: 0];
	assign data_write_ptag = doutb[87: 68];
	assign wdata_uncache = doutb[88];
	assign data_abandon_lookup = 1'b0;
	assign data_clear = clear;
	assign vwtag = write_addr[31: 12];

	assign ena = 1'b1;
	assign enb = 1'b1;
	assign wea = pre_write_ready;
	assign dina = {data_uncache, pwtag, write_wstrb, write_addr, write_store_data};
	assign addra = wp_tail;
	assign addrb = wp_head;

	assign state_read_idle = read_state == READ_IDLE;
	assign state_read_busy = read_state == READ_BUSY;

	assign inst1_store = en1 & store1;
	assign inst1_load = en1 & load1;
	assign inst2_store = en2 & store2;
	assign inst2_load = en2 & load2;
	assign inst1_retire = retire_en1 && write_en[write_retire_tail] && !(write_buffer[write_retire_tail].sc && !write_buffer[write_retire_tail].llbit) && write_buffer[write_retire_tail].rob_index == retire_rob_index1;
	assign inst2_retire = retire_en2 && (!inst1_retire ? write_en[write_retire_tail] && !(write_buffer[write_retire_tail].sc && !write_buffer[write_retire_tail].llbit) &&  write_buffer[write_retire_tail].rob_index == retire_rob_index2 : write_en[write_retirep1] && !(write_buffer[write_retirep1].sc && !write_buffer[write_retirep1].llbit) && write_buffer[write_retirep1].rob_index == retire_rob_index2);

	assign mem_end = (read_en[read_tail] & read_buffer[read_tail].data_ready & is_read_tail) | (write_buffer[write_wb_tail].wb_ready & write_en[write_wb_tail] & ~write_buffer[write_wb_tail].in_store);
	assign requestor = !(read_en[read_tail] & read_buffer[read_tail].data_ready & is_read_tail);
	assign next_mem_rd = requestor ? 0 : read_buffer[read_tail].rd;

	assign read_add_num[1] = inst1_load & inst2_load;
	assign read_add_num[0] = inst1_load ^ inst2_load;
	assign write_add_num[1] = inst1_store & inst2_store;
	assign write_add_num[0] = inst1_store ^ inst2_store;
	assign index_add_num[1] = en1 & en2;
	assign index_add_num[0] = en1 ^ en2;
	assign retire_num[1] = inst1_retire & inst2_retire;
	assign retire_num[0] = inst1_retire ^ inst2_retire;

	assign wp_retire_tailp1 = wp_retire_tail + 1;	
	assign wp_clear_head = wp_head + write_ok;
	assign wp_retire_clear_tail = wp_retire_tail + retire_num;
	assign read_indexp1 = inst1_load & inst2_load ? read_head + 1 : read_head;
	assign write_indexp1 = inst1_store & inst2_store ? write_head + 1 : write_head;
	assign current_indexp1 = en1 & en2 ? current_index + 1 : current_index;
	assign write_tailp1 = write_tail + 1;
	assign write_retirep1 = write_retire_tail + 1;
	assign write_tail_next = inst1_retire && inst2_retire ? write_retirep1 : write_retire_tail;
	assign read_headp1 = read_head + 1;
	assign directionp1 = en1 && en2 && current_index == 4'b1111 ? ~direction : direction;
	assign clear_retire_tail = write_retire_tail + inst1_retire + inst2_retire;
	assign clear_write_tail = write_tail + write_ok;
	assign write_en_mask = (((9'b1 << clear_retire_tail) - 1) ^ ((9'b1 << clear_write_tail) - 1));

	assign write_ready = write_en[write_search_tail] & write_buffer[write_search_tail].rs_ready & write_buffer[write_search_tail].rt_ready & ~write_buffer[write_search_tail].wb_ready;
	// assign write_addr = write_offset + data1;
	// assign write_addr_offset = write_offset[1: 0] + data1[1: 0];


	assign writeable = (write_buffer[pre_search_tail].sc & ~write_buffer[pre_search_tail].llbit) | is_write_tail & ~wp_full & ((|wr_conflict) | (~(|wr_conflict)) & (~(&store_buffer_en)));
	assign need_write = pre_write_ready & ~(write_buffer[pre_search_tail].sc & ~write_buffer[pre_search_tail].llbit) & ~wp_full & is_write_tail & (~(|wr_conflict)) & (~(&store_buffer_en));
	assign store_valid = pre_write_ready & writeable;
	assign write_wstrb = swl ? 4'b1111 << write_addr_offset : swr ? 4'b1111 >> (2'b11 - write_addr_offset) : write_size == 2'b00 ? (4'b0001 << write_addr_offset) : write_size == 2'b01 ? (4'b0011) << write_addr_offset : 4'b1111;
	assign write_ok = write_accept | data_write_req & data_waddr_ok & wdata_uncache;
	assign prf_write_addr = write_buffer[write_search_tail].offset + data1;
	assign clear_remain_count = clear_write_tail + BUFFER_SIZE - clear_retire_tail;
	assign write_out_exccode = write_buffer[write_wb_tail].tlb_invalid ? `EXC_ITLBS : write_buffer[write_wb_tail].tlb_refill ? `EXC_RTLBS : write_buffer[write_wb_tail].tlb_modify ? `EXC_MOD : write_buffer[write_wb_tail].exccode;
	assign read_out_exccode = read_buffer[read_tail].tlb_invalid ? `EXC_ITLBL : read_buffer[read_tail].tlb_refill ? `EXC_RTLBL : read_exccode;
	assign out_exccode = requestor ? write_out_exccode : read_out_exccode;
	for(genvar i=0; i<STORE_BUFFER_SIZE; i++)begin
		assign wr_conflict[i] = store_buffer_en[i] & (store_buffer[i].addr == write_addr[31: 2]);
		assign read_conflict[i] = store_buffer_en[i] & (store_buffer[i].addr == read_addr[31: 2] & ((store_buffer[i].wstrb & read_wstrb) == read_wstrb));
		assign read_relavant[i] = store_buffer_en[i] & (store_buffer[i].addr == read_addr[31 :2] & (|(store_buffer[i].wstrb & read_wstrb)));
		assign store_buffer_en_mask[i] = write_ok && store_buffer_en[i] && store_buffer[i].index == wp_head;
		assign store_backup_en_mask[i] = write_ok && store_backup_en[i] && store_backup_buffer[i].index == wp_head;
	end
	encoder_4to2 encoder_store_index(wr_conflict, store_index);
	encoder_4to2 encoder_conflict_index(read_relavant, conflict_index);
	StoreResolveUtil store_resolve_util(store_uncache, write_addr[15: 2], store_buffer[store_index].data, write_data, write_addr_offset, write_wstrb, store_combine_data);
	StoreResolveUtil store_resolve2(store_uncache, write_addr[15: 2], 0, write_data, write_addr_offset, write_wstrb, write_store_data);
	MemExcResolveUtil read_exccode_resolve(read_buffer[read_tail].lwl | read_buffer[read_tail].lwr, read_buffer[read_tail].exccode, 1'b0, read_buffer[read_tail].size, read_buffer[read_tail].addr[1: 0], read_exccode);
	MemExcResolveUtil write_exccode_resolve(write_buffer[pre_search_tail].swl | write_buffer[pre_search_tail].swr, write_buffer[pre_search_tail].exccode, 1'b1, write_buffer[pre_search_tail].size, write_addr[1: 0], write_exccode);
	priority_encoder_4to2 encoder_store_free_index((~store_buffer_en), store_free_index);
	priority_encoder_8to3 encoder_read_index(read_ready, read_index_encode);
	
	assign read_ready = read_en & read_rs_ready & read_rt_ready & ~in_reorder & reorderable;
	assign read_index = read_ready[read_search_tail] ? read_search_tail : read_index_encode;
	assign read_addr = store_data3 + read_offset; 
	assign read_addr_offset = store_data3[1 :0] + read_offset[1: 0];
	assign read_exception = !read_buffer[addr_read_index].lwl && !read_buffer[addr_read_index].lwr && (read_buffer[addr_read_index].size == 2'b01 && (read_addr_offset == 2'b01 || read_addr_offset == 2'b11) || read_buffer[addr_read_index].size == 2'b10 && (read_addr_offset != 2'b00));
	assign read_uncache = (read_addr[31] & ~read_addr[30] & read_addr[29] & ~read_addr[28] | read_addr[23] & read_addr[21] & ~read_addr[20]);
	assign write_uncache = data_waddr[31] & ~data_waddr[30] & data_waddr[29] & ~data_waddr[28] | data_waddr[23] & data_waddr[21] & ~data_waddr[20];
	assign store_uncache = write_addr[31] & ~write_addr[30] & write_addr[29] & ~write_addr[28] | write_addr[23] & write_addr[21] & ~write_addr[20];
	// assign read_addr_offset = read_addr[1: 0];
	assign read_wstrb = read_buffer[addr_read_index].size == 2'b00 ? (4'b0001 << read_addr_offset) : read_buffer[addr_read_index].size == 2'b01 ? (4'b0011) << read_addr_offset : 4'b1111;
	assign  wr_addr_conflict= (store_valid && read_addr[31 :2] == write_addr[31: 2] && !(tail_read & ~is_write_tail_next));
	assign is_read_tail = !write_en[write_wb_tail] || (write_en[write_wb_tail] && write_buffer[write_wb_tail].in_store || write_direction[write_wb_tail] == read_direction[read_tail] && write_index[write_wb_tail] > read_buffer[read_tail].index || write_direction[write_wb_tail] != read_direction[read_tail] && write_index[write_wb_tail] < read_buffer[read_tail].index);
	assign is_write_tail = !read_en[read_search_tail] || write_en[pre_search_tail] && read_en[read_search_tail] && (write_direction[pre_search_tail] == read_direction[read_search_tail] && write_index[pre_search_tail] < read_buffer[read_search_tail].index || write_direction[pre_search_tail] != read_direction[read_search_tail] && write_index[pre_search_tail] > read_buffer[read_search_tail].index);
	assign next_store_backup_en = (store_backup_en & (~store_backup_en_mask)) | 
			{STORE_BUFFER_SIZE{inst1_retire}} & (1 << write_buffer[write_retire_tail].store_index) | {STORE_BUFFER_SIZE{inst2_retire}} & (1 << write_buffer[write_tail_next].store_index);


	LoadResolveUtil load_resolve_util(snap_outb, data_rdata, read_combine_data);
	DataResolveUtil data_resolve_util(read_buffer[read_tail].size, read_buffer[read_tail].is_unsigned, read_buffer[read_tail].lwl, read_buffer[read_tail].lwr, read_buffer[read_tail].addr[1: 0], read_buffer[read_tail].data, read_buffer[read_tail].rt_data, read_out_data);

	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == 1'b0 || cp0_clear)begin
			llbit <= 1'b0;
			retire_llbit <= 1'b0;
		end
		else if(branch_fail_clear)begin
			llbit <= retire_llbit;
		end
		else begin
			llbit <= inst2_load && inst2_memop == `MEMOP_LL ? 1'b1 : 
					inst2_store && inst2_memop == `MEMOP_SC ? 1'b0 :
					inst1_load && inst1_memop == `MEMOP_LL ? 1'b1 :
					inst1_store && inst1_memop == `MEMOP_SC ? 1'b0 : llbit;
			
			retire_llbit <= retire_ll2 ? 1'b1 : 
							inst2_retire && write_buffer[write_tail_next].sc ? 1'b0 :
							retire_ll1 ? 1'b1 :
							inst1_retire && write_buffer[write_tail].sc ? 1'b0 : retire_llbit;
		end
	end

	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == 1'b0)begin
			for(int i=0; i<BUFFER_SIZE; i++)begin
				write_buffer[i] <= 0;
			end
			write_head <= 0;
			write_tail <= 0;
			write_retire_tail <= 0;
			write_search_tail <= 0;
			write_wb_tail <= 0;
			write_remain_count <= BUFFER_SIZE;
			write_lock <= 0;
			write_en <= 0;
			current_index <= 0;
			for(int i=0; i<STORE_BUFFER_SIZE; i++)begin
				store_backup_buffer[i] <= 0;
				store_buffer[i] <= 0;
			end
			store_backup_en <= 0;
			store_buffer_en <= 0;
			wp_tail <= 0;
			wp_head <= 0;
			wp_retire_tail <= 0;
			write_placehold_en <= 0;
		end
		else if(clear)begin
			write_retire_tail <= 0;
			write_head <= 0;
			write_search_tail <= 0;
			write_remain_count <= BUFFER_SIZE;
			write_wb_tail <= 0;
			write_en <= 0;
			current_index <= 0;
			write_tail <= 0;
			store_backup_en <= next_store_backup_en;
			store_buffer_en <= next_store_backup_en;
			wp_head <= wp_clear_head;
			wp_tail <= wp_retire_clear_tail;
			wp_retire_tail <= wp_retire_clear_tail;
			write_placehold_en <= wp_clear_head == wp_retire_clear_tail && write_placehold_en[wp_clear_head] ? 8'hff : wp_retire_clear_tail >= wp_clear_head ? write_placehold_en_mask : ~write_placehold_en_mask;
		end
		else begin
			write_remain_count <= write_remain_count - {write_add_num & {2{~stall}}} + inst1_retire + inst2_retire;
			write_head <= write_head + (write_add_num & {2{~stall}});
			write_tail <= write_tail + retire_num;
			write_retire_tail <= write_retire_tail + inst1_retire + inst2_retire;
			write_search_tail <= write_search_tail + (write_ready & writeable);
			write_wb_tail <= write_wb_tail + (requestor & inst_wb_receive);
			wp_retire_tail <= wp_retire_tail + retire_num;
			wp_head <= wp_head + write_ok;
			current_index <= current_index + (index_add_num & {2{~stall}});

			if(requestor & inst_wb_receive)begin
				write_buffer[write_wb_tail].in_store <= 1'b1;
			end
			if(store_valid)begin
				write_buffer[pre_search_tail].wb_ready <= 1'b1;
				write_buffer[pre_search_tail].exccode <= write_exccode;
				write_buffer[pre_search_tail].addr <= write_addr;
				write_buffer[pre_search_tail].store_index <=  need_write ? store_free_index : store_index;
				write_buffer[pre_search_tail].wp_index <= wp_tail;
				write_buffer[pre_search_tail].store_data <= need_write ? write_store_data : store_combine_data;
				write_buffer[pre_search_tail].store_wstrb <= need_write ? write_wstrb : store_buffer[store_index].wstrb | write_wstrb;
				write_buffer[pre_search_tail].tlb_refill <= wdata_tlb_refill;
				write_buffer[pre_search_tail].tlb_invalid <= wdata_tlb_invalid;
				write_buffer[pre_search_tail].tlb_modify <= data_tlb_modify;
				if(!(write_buffer[pre_search_tail].sc && !write_buffer[pre_search_tail].llbit))begin
					wp_tail <= wp_tail + 1;
				end
			end
			store_buffer_en <= (store_buffer_en & (~store_buffer_en_mask)) | {STORE_BUFFER_SIZE{need_write}} & (1 << store_free_index) | ({STORE_BUFFER_SIZE{pre_write_ready & (|wr_conflict) & is_write_tail}} & (1 << store_index));
			if(next_clear)begin
				for(int i=0; i<STORE_BUFFER_SIZE; i++)begin
					store_buffer[i] <= store_backup_buffer[i];
				end
			end
			if(need_write)begin
				store_buffer[store_free_index].index <= wp_tail;
				store_buffer[store_free_index].addr <= write_addr[31: 2];
				store_buffer[store_free_index].data <= write_store_data;
				store_buffer[store_free_index].wstrb <= write_wstrb;
			end
			if(pre_write_ready & (|wr_conflict) & is_write_tail & ~(write_buffer[pre_search_tail].sc & ~write_buffer[pre_search_tail].llbit))begin
				store_buffer[store_index].data <= store_combine_data;
				store_buffer[store_index].wstrb <= store_buffer[store_index].wstrb | write_wstrb;
				store_buffer[store_index].index <= wp_tail;
			end

			if(inst1_retire && inst2_retire)begin
				write_placehold_en[wp_retire_tail] <= 1'b1;
				write_placehold_en[wp_retire_tailp1] <= 1'b1;
			end
			else if(inst1_retire || inst2_retire)begin
				write_placehold_en[wp_retire_tail] <= 1'b1;
			end
			if(write_ok)begin
				write_placehold_en[wp_head] <= 1'b0;
			end
			if(inst1_retire)begin
				write_en[write_retire_tail] <= 1'b0;
				store_backup_buffer[write_buffer[write_retire_tail].store_index] <= {write_buffer[write_retire_tail].wp_index, write_buffer[write_retire_tail].addr[31: 2], write_buffer[write_retire_tail].store_data, write_buffer[write_retire_tail].store_wstrb};
			end
			if(inst2_retire)begin
				write_en[write_tail_next] <= 1'b0;
				store_backup_buffer[write_buffer[write_tail_next].store_index] <= {write_buffer[write_tail_next].wp_index, write_buffer[write_tail_next].addr[31: 2], write_buffer[write_tail_next].store_data, write_buffer[write_tail_next].store_wstrb};
			end
			store_backup_en <= (store_backup_en & (~store_backup_en_mask)) | 
			{STORE_BUFFER_SIZE{inst1_retire}} & (1 << write_buffer[write_retire_tail].store_index) | {STORE_BUFFER_SIZE{inst2_retire}} & (1 << write_buffer[write_tail_next].store_index);
			if(inst1_store & ~stall)begin
				write_en[write_head] <= 1'b1;
				write_buffer[write_head].wb_ready <= 1'b0;
				write_buffer[write_head].rs_ready <= inst1_rs_ready;
				write_buffer[write_head].rt_ready <= inst1_rt_ready;
				write_buffer[write_head].exccode <= inst1_exccode;
				write_buffer[write_head].in_store <= 1'b0;
				// write_buffer[write_head].ready <= 1'b0;
				write_buffer[write_head].wb_ready <= 1'b0;
				write_buffer[write_head].rs <= inst1_rs;
				write_buffer[write_head].rt <= inst1_rt;
				write_buffer[write_head].rd <= inst1_rd;
				write_buffer[write_head].rob_index <= rob_index1;
				write_buffer[write_head].offset <= inst1_src2;
				write_buffer[write_head].size <= inst1_memsize;
				write_buffer[write_head].swl <= inst1_memop == `MEMOP_SWL;
				write_buffer[write_head].swr <= inst1_memop == `MEMOP_SWR;
				write_buffer[write_head].sc <= inst1_memop == `MEMOP_SC;
				write_buffer[write_head].llbit <= llbit;
				write_buffer[write_head].tlb_invalid <= 1'b0;
				write_buffer[write_head].tlb_refill <= 1'b0;
				write_buffer[write_head].tlb_modify <= 1'b0;
			end
			if(inst2_store & ~stall)begin
				write_en[write_indexp1] <= 1'b1;
				write_buffer[write_indexp1].wb_ready <= 1'b0;
				write_buffer[write_indexp1].rs_ready <= inst2_rs_ready;
				write_buffer[write_indexp1].rt_ready <= inst2_rt_ready;
				write_buffer[write_indexp1].exccode <= inst2_exccode;
				write_buffer[write_indexp1].in_store <= 1'b0;
				// write_buffer[write_indexp1].ready <= 1'b0;
				write_buffer[write_indexp1].wb_ready <= 1'b0;
				write_buffer[write_indexp1].rs <= inst2_rs;
				write_buffer[write_indexp1].rt <= inst2_rt;
				write_buffer[write_indexp1].rd <= inst2_rd;
				write_buffer[write_indexp1].rob_index <= rob_index2;
				write_buffer[write_indexp1].offset <= inst2_src2;	
				write_buffer[write_indexp1].size <= inst2_memsize;	
				write_buffer[write_indexp1].swl <= inst2_memop == `MEMOP_SWL;
				write_buffer[write_indexp1].swr <= inst2_memop == `MEMOP_SWR;	
				write_buffer[write_indexp1].sc <= inst2_memop == `MEMOP_SC;
				write_buffer[write_indexp1].llbit <= inst1_load && inst1_memop == `MEMOP_LL || llbit;
				write_buffer[write_indexp1].tlb_refill <= 1'b0;
				write_buffer[write_indexp1].tlb_invalid <= 1'b0;
				write_buffer[write_indexp1].tlb_modify <= 1'b0;
			end
			for(int i=0; i<BUFFER_SIZE; i++)begin
				if(write_en[i])begin
					write_buffer[i].rs_ready <= write_buffer[i].rs_ready | (wb_en1 && write_buffer[i].rs == wb_rd1) | (wb_en2 && write_buffer[i].rs == wb_rd2) | (wb_en3 && write_buffer[i].rs == wb_rd3);
					write_buffer[i].rt_ready <= write_buffer[i].rt_ready | (wb_en1 && write_buffer[i].rt == wb_rd1) | (wb_en2 && write_buffer[i].rt == wb_rd2) | (wb_en3 && write_buffer[i].rt == wb_rd3);
				end
				// if(write_en[i] && (write_buffer[i].rs == wb_rd1 || write_buffer[i].rs == wb_rd2))begin
				// 	write_buffer[i].rs_ready <= 1'b1;
				// end
				// if(write_en[i] && (write_buffer[i].rt == wb_rd1 || write_buffer[i].rt == wb_rd2))begin
				// 	write_buffer[i].rt_ready <= 1'b1;
				// end
			end
		end
	end

	always_ff @(posedge cpu_clk)begin
		// write_size <= write_buffer[write_search_tail].size;
		pre_addr_ok <= data_addr_ok;
		next_clear <= clear;
		if(cpu_rst_n == 1'b0 || clear)begin
			for(int i=0; i<BUFFER_SIZE; i++)begin
				read_buffer[i] <= 0;
			end
			read_en <= 0;
			read_rs_ready <= 0;
			read_rt_ready <= 0;
			in_reorder <= 0;
			reorderable <= 8'hff;
			read_direction <= 0;
			read_head <= 0;
			read_tail <= 0;
			read_remain_count <= BUFFER_SIZE;
			data_req <= 1'b0;
			data_addr <= 0;
			// next_compare <= 0;
			// store_read_addr <= 0;
			// store_read_wstrb <= 0;
			write_addr <= 0;
			write_data <= 0;
			write_size <= 0;
			write_addr_offset <= 0;
			pre_write_ready <= 0;
			pre_search_tail <= 0;
			mem_rd <= 0;
			direction <= 0;
			store_data3 <= 0;
			enable_miss <= 0;
			mem_rob_index <= 0;
			out_queue_index <= 0;
			data_rwstrb <= 0;
			read_offset <= 0;
			mem_addr <= 0;
			on_exception <= 0;
			vaddr_we <= 0;
			entryhi_we <= 0;
			addr_read_index <= 0;
			addr_read_ready <= 0;
			// read_addr <= 0;
			rd_abandon <= 0;
			abandon_index <= 0;
			write_index <= 32'h76543210;
			write_direction <= 0;
			tail_read <= 0;
			read_search_tail <= 0;
			is_write_tail_next <= 0;
			mem_exccode <= `EXC_NONE;
			read_searching <= 0;
			searching_conflict <= 0;
			searching_relavant <= 0;
			searching_wstrb <= 0;
			read_state <= READ_IDLE;
			swl <= 0;
			swr <= 0;
			mem_data <= 0;
		end
		else begin
			read_remain_count <= read_remain_count - (read_add_num & {2{~stall}}) + (inst_wb_receive & ~requestor);
			read_head <= read_head + (read_add_num & {2{~stall}});
			read_tail <= read_tail + (inst_wb_receive & ~requestor);
			read_search_tail <= read_search_tail + ((data_addr_ok | addr_read_ready & ((|read_conflict) | wr_addr_conflict)) & read_en[read_search_tail] & read_rs_ready[read_search_tail] & read_rt_ready[read_search_tail] & ~in_reorder[read_search_tail] & ~is_write_tail) + (inst_wb_receive & ~requestor & ~read_buffer[read_tail].force_search);

			mem_rd <= requestor ? (write_buffer[write_wb_tail].sc ? write_buffer[write_wb_tail].rd : 0) : read_buffer[read_tail].rd;
			mem_rob_index <= requestor ? write_buffer[write_wb_tail].rob_index : read_buffer[read_tail].rob_index;
			mem_data <= requestor ? write_buffer[write_wb_tail].sc & write_buffer[write_wb_tail].llbit : read_out_data;
			mem_exccode <= out_exccode;
			mem_addr <= requestor ? write_buffer[write_wb_tail].addr : read_buffer[read_tail].addr;
			on_exception <= mem_end && (out_exccode == `EXC_AdEL || out_exccode == `EXC_AdES || out_exccode == `EXC_ITLBL || out_exccode == `EXC_ITLBS || out_exccode == `EXC_MOD || out_exccode == `EXC_RTLBL || out_exccode == `EXC_RTLBS) ? 1'b1 : on_exception;
			vaddr_we <= !on_exception && mem_end && (out_exccode == `EXC_AdEL || out_exccode == `EXC_AdES || out_exccode == `EXC_ITLBL || out_exccode == `EXC_ITLBS || out_exccode == `EXC_MOD || out_exccode == `EXC_RTLBL || out_exccode == `EXC_RTLBS);
			entryhi_we <= !on_exception && mem_end && (out_exccode == `EXC_ITLBL || out_exccode == `EXC_ITLBS || out_exccode == `EXC_MOD || out_exccode == `EXC_RTLBL || out_exccode == `EXC_RTLBS);
			//exe_exe_exccode1 <= store_req ? store_buffer[store].exccode_s:

			if(!stall && (current_index == 4'b1110 && index_add_num == 2'b10 || current_index == 4'b1111 && index_add_num != 2'b00))begin
				direction <= ~direction;
			end
			if(inst1_store & ~stall)begin
				write_direction[write_head] <= direction;
				write_index[write_head] <= current_index;
			end
			if(inst2_store & ~stall)begin
				write_direction[write_indexp1] <= directionp1;
				write_index[write_indexp1] <= current_indexp1;				
			end

			if(inst_wb_receive & ~requestor)begin
				read_en[read_tail] <= 1'b0;
			end
			if(addr_read_ready & (wr_addr_conflict | read_exception))begin
				in_reorder[addr_read_index] <= 1'b0;
				read_buffer[addr_read_index].data_ready <= addr_read_ready & read_exception;
			end
			else if(|read_conflict & read_searching)begin
				read_buffer[addr_read_index].data_ready <= 1'b1;
				read_buffer[addr_read_index].data <= store_buffer[conflict_index].data;
				in_reorder[addr_read_index] <= 1'b1;
			end
			if(data_data_ok && data_success && in_reorder[read_queue_index])begin
				read_buffer[read_queue_index].data_ready <= 1'b1;
				read_buffer[read_queue_index].data <= read_combine_data;
			end
			if(mshr_data_ok)begin
				read_buffer[mshr_queue_index].data_ready <= 1'b1;
				read_buffer[mshr_queue_index].data <= mshr_data;
			end
			if(data_data_ok && !data_success && !(rdata_tlb_invalid | rdata_tlb_refill))begin
				in_reorder[read_queue_index] <= 1'b0;
			end
			if(data_data_ok & ~data_success & (rdata_tlb_invalid | rdata_tlb_refill))begin
				read_buffer[read_queue_index].data_ready <= 1'b1;
			end
			if(data_data_ok & ~data_success)begin
				read_buffer[read_queue_index].tlb_refill <= rdata_tlb_refill;
				read_buffer[read_queue_index].tlb_invalid <= rdata_tlb_invalid;
			end
			if(data_data_ok)begin
				reorderable[read_queue_index] <= 1'b1;
			end

			read_searching <= (data_addr_ok | read_searching & (|read_conflict) | addr_read_ready & wr_addr_conflict) & (|read_ready);
			if(read_searching)begin
				searching_conflict <= |read_conflict;
				searching_relavant <= |read_relavant;
				searching_wstrb <= store_buffer[conflict_index].wstrb;
				read_buffer[addr_read_index].rt_data <= data4;
			end
			if(data_addr_ok | read_searching & (|read_conflict) | addr_read_ready & wr_addr_conflict)begin
				// next_compare <= compare31;
				addr_read_ready <= |read_ready;
				tail_read <= read_en[read_search_tail] & read_rs_ready[read_search_tail] & read_rt_ready[read_search_tail] & ~in_reorder[read_search_tail];
				is_write_tail_next <= is_write_tail;
				addr_read_index <= read_index;
				store_data3 <= data3;
				// read_addr <= data3 + read_buffer[read_index].offset;
				// data_addr <= read_addr;
				// data_req <= addr_read_ready & (~wr_addr_conflict) & (~(|read_conflict)) & ~read_exception & (~read_uncache | read_uncache & tail_read & ~is_write_tail_next);
				read_offset <= read_buffer[read_index].offset;
				// data_rwstrb <= read_wstrb & (~({4{|read_relavant}} & store_buffer[conflict_index].wstrb));
				// out_queue_index <= addr_read_index;
				// enable_miss <= tail_read & ~is_write_tail_next;
			end
	
			if(data_addr_ok)begin
				data_addr <= read_addr;
				data_req <= addr_read_ready & (~wr_addr_conflict) & (~(read_searching & (|read_conflict))) & ~read_exception;
				data_rwstrb <= read_wstrb & (~({4{read_searching & (|read_relavant) | ~read_searching & searching_relavant}} & (read_searching ? store_buffer[conflict_index].wstrb : searching_wstrb)));
				out_queue_index <= addr_read_index;
				enable_miss <= tail_read & ~is_write_tail_next;
			end
			if(read_en[read_search_tail] & read_rs_ready[read_search_tail] & read_rt_ready[read_search_tail] & ~in_reorder[read_search_tail])begin
				read_buffer[read_search_tail].force_search <= ~is_write_tail;
			end
			
			if((|read_ready) && data_addr_ok)begin
				in_reorder[read_index] <= 1'b1;
			end
			if(addr_read_ready)begin
				read_buffer[addr_read_index].addr <= read_addr;
			end

			if(writeable)begin
				write_addr <= write_buffer[write_search_tail].offset + data1;
				write_addr_offset <= write_buffer[write_search_tail].offset[1: 0] + data1[1: 0];
				swl <= write_buffer[write_search_tail].swl;
				swr <= write_buffer[write_search_tail].swr;
				write_data <= data2;
				write_size <= write_buffer[write_search_tail].size;
				pre_write_ready <= write_ready;
				pre_search_tail <= write_search_tail;
			end

			for(int i=0; i<BUFFER_SIZE; i++)begin
				if((pre_write_ready && writeable) && read_en[i] && !read_buffer[i].force_search && read_buffer[i].addr[31: 2] == write_addr[31: 2])begin
					in_reorder[i] <= 1'b0;
					reorderable[i] <= !(data_req && out_queue_index == i && !data_addr_ok);
					read_buffer[i].data_ready <= 1'b0;
				end
			end
			

			if(inst1_load & ~stall)begin
				read_en[read_head] <= 1'b1;
				read_rs_ready[read_head] <= inst1_rs_ready;
				read_rt_ready[read_head] <= inst1_memop != `MEMOP_LWL && inst1_memop != `MEMOP_LWR || inst1_rt_ready;
				read_buffer[read_head].data_ready <= 1'b0;
				in_reorder[read_head] <= 1'b0;
				read_buffer[read_head].is_unsigned <= inst1_unsigned;
				read_buffer[read_head].force_search <= 0;
				read_direction[read_head] <= direction;
				read_buffer[read_head].index <= current_index;
				read_buffer[read_head].rs <= inst1_rs;
				read_buffer[read_head].rt <= inst1_rt;
				read_buffer[read_head].rd <= inst1_rd;
				read_buffer[read_head].rob_index <= rob_index1;
				read_buffer[read_head].offset <= inst1_src2;
				read_buffer[read_head].size <= inst1_memsize;
				read_buffer[read_head].addr <= 0;
				read_buffer[read_head].exccode <= inst1_exccode;
				read_buffer[read_head].lwl <= inst1_memop == `MEMOP_LWL;
				read_buffer[read_head].lwr <= inst1_memop == `MEMOP_LWR;
				read_buffer[read_head].tlb_refill <= 1'b0;
				read_buffer[read_head].tlb_invalid <= 1'b0;
			end
			if(inst2_load & ~stall)begin
				read_en[read_indexp1] <= 1'b1;
				read_rs_ready[read_indexp1] <= inst2_rs_ready;
				read_rt_ready[read_indexp1] <= inst2_memop != `MEMOP_LWL && inst2_memop != `MEMOP_LWR || inst2_rt_ready;
				read_buffer[read_indexp1].data_ready <= 1'b0;
				in_reorder[read_indexp1] <= 1'b0;
				read_buffer[read_indexp1].is_unsigned <= inst2_unsigned;
				read_buffer[read_indexp1].force_search <= 0;
				read_direction[read_indexp1] <= directionp1;
				read_buffer[read_indexp1].index <= current_indexp1;
				read_buffer[read_indexp1].rs <= inst2_rs;
				read_buffer[read_indexp1].rt <= inst2_rt;
				read_buffer[read_indexp1].rd <= inst2_rd;
				read_buffer[read_indexp1].rob_index <= rob_index2;
				read_buffer[read_indexp1].offset <= inst2_src2;
				read_buffer[read_indexp1].size <= inst2_memsize;
				read_buffer[read_indexp1].addr <= 0;
				read_buffer[read_indexp1].exccode <= inst2_exccode;
				read_buffer[read_indexp1].lwl <= inst2_memop == `MEMOP_LWL;
				read_buffer[read_indexp1].lwr <= inst2_memop == `MEMOP_LWR;
				read_buffer[read_indexp1].tlb_refill <= 1'b0;
				read_buffer[read_indexp1].tlb_invalid <= 1'b0;
			end

			for(int i=0; i<BUFFER_SIZE; i++)begin
				if(read_en[i])begin
					read_rs_ready[i] <= read_rs_ready[i] || (wb_en1 && read_buffer[i].rs == wb_rd1) || (wb_en2 && read_buffer[i].rs == wb_rd2) || (wb_en3 && read_buffer[i].rs == wb_rd3);
					read_rt_ready[i] <= read_rt_ready[i] || (wb_en1 && read_buffer[i].rt == wb_rd1) || (wb_en2 && read_buffer[i].rt == wb_rd2) || (wb_en3 && read_buffer[i].rt == wb_rd3);
				end
				// if(read_en[i] && (read_buffer[i].rs == wb_rd1 || read_buffer[i].rs == wb_rd2))begin
				// 	read_rs_ready[i] <= 1'b1;
				// end
			end
		end
	end
endmodule

module DataResolveUtil(
	input logic [1: 0] size,
	input logic unsign_exetand,
	input logic lwl,
	input logic lwr,
	input logic [1: 0] offset,
	input logic [3: 0][7: 0] data,
	input logic [31: 0] rt_data,
	output logic [31: 0] out_data
);
	logic [4: 0] shift_offsetl, shift_offsetr;
	logic [7: 0] byte_data;
	logic [15 :0] half_data;
	logic [31: 0] normal_data, unalign_data, shift_data;
	assign byte_data = data[offset];
	assign half_data = offset[1] == 0 ? {data[1], data[0]} : {data[3], data[2]};
	always_comb begin
		case(size)
		2'b00: begin
			if(unsign_exetand)begin
				normal_data = {24'h000000, byte_data};
			end
			else begin
				normal_data = byte_data[7] == 1'b1 ? {24'hffffff, byte_data} : {24'h000000, byte_data};
			end
		end
		2'b01: begin
			if(unsign_exetand)begin
				normal_data = {16'h0000, half_data};
			end
			else begin
				normal_data = half_data[15] == 1'b1 ? {16'hffff, half_data} : {16'h0000, half_data};
			end
		end
		3'b10: begin
			normal_data = data;
		end
		default: normal_data = 0;
		endcase
	end
	assign shift_offsetl = offset << 3;
	assign shift_offsetr = (2'b11 - offset) << 3;
	assign shift_data = lwl ? data << shift_offsetl : data >> shift_offsetr;
	assign unalign_data = shift_data | rt_data;
	assign out_data = lwl | lwr ? unalign_data : normal_data;
endmodule

module StoreResolveUtil(
	input logic is_uncache,
	input logic [13: 0] uncache_offset,
	input logic [31: 0] origin_data,
	input logic [31: 0] input_data,
	input logic [1: 0] offset,
	input logic [3: 0] wstrb,
	output logic [31: 0] combine_data
);
	logic [31: 0] expand_wstrb;
	logic [31: 0] shift_data;
	logic [4: 0] shift_offset;
	logic [31: 0] uncache_data;
	always_comb begin
		case (uncache_offset)
			14'h3ffc : uncache_data = {24'd0,shift_data[7: 0]} ;
			14'h3ffe : uncache_data = {31'd0,|shift_data} ;
			14'h3fff: uncache_data = {31'd0,shift_data[0]} ;
			14'h3ffb: uncache_data = {shift_data[15: 0], shift_data[31: 16]};
			default: uncache_data = shift_data;
		endcase
	end
	bit_expander_4to32 expander(wstrb, expand_wstrb);
	assign shift_offset = offset << 3;
	assign shift_data = input_data << shift_offset;
	// assign combine_data = origin_data & (~expand_wstrb) | shift_data & (expand_wstrb);
	assign combine_data = is_uncache ? origin_data & (~expand_wstrb) | uncache_data & expand_wstrb :
	origin_data & (~expand_wstrb) | shift_data & (expand_wstrb);
endmodule

module LoadResolveUtil(
	input logic [35: 0] origin_data,
	input logic [31: 0] input_data,
	output logic [31: 0] out_data
);
	logic [31: 0] expand_wstrb;
	bit_expander_4to32 expander(origin_data[3: 0], expand_wstrb);
	assign out_data = origin_data[35: 4] & (expand_wstrb) | input_data & (~expand_wstrb);
endmodule

// buffer_index, rs, direction, valid, index 
// buffer_index: 14-12 rs: 11: 6 direction: 5 valid: 4 index: 3: 0
module MemCompareUtil#(
	parameter BUFFER_INDEX_WIDTH=3,
	parameter INDEX_WIDTH=4,
	parameter VALID=INDEX_WIDTH,
	parameter DIRECTION=INDEX_WIDTH+1,
	parameter RS_BEGIN=INDEX_WIDTH+2,
	parameter RS_END=INDEX_WIDTH+7,
	parameter BUFFER_END=BUFFER_INDEX_WIDTH+INDEX_WIDTH+1,
	parameter BUFFER_BEGIN=BUFFER_INDEX_WIDTH+INDEX_WIDTH-1
)(
	input logic [BUFFER_INDEX_WIDTH+INDEX_WIDTH+7: 0] input_compare1,
	input logic [BUFFER_INDEX_WIDTH+INDEX_WIDTH+7: 0] input_compare2,
	output logic [BUFFER_INDEX_WIDTH+INDEX_WIDTH+7: 0] compare
);
	always_comb begin
		if(input_compare1[VALID] & ~input_compare2[VALID] | input_compare1[VALID] & input_compare2[VALID] & ((input_compare1[DIRECTION] != input_compare2[DIRECTION]) ^ (input_compare1[INDEX_WIDTH-1: 0] < input_compare2[INDEX_WIDTH-1: 0])))begin
			compare = input_compare1;
		end
		else begin
			compare = input_compare2;
		end
	end
endmodule

module MemCompareUtil2#(
	parameter BANK_NUM=6
)(
	input logic [BANK_NUM-1: 0] ready,
	input logic [BANK_NUM-1: 0][5: 0] index,
	input logic [BANK_NUM-1: 0] direction,
	output logic [BANK_NUM-1: 0] select
);
	logic [27: 0] bigger;
	assign bigger[0] = ((direction[0] != direction[1]) ^ (index[0] < index[1]));
	assign bigger[1] = ((direction[0] != direction[2]) ^ (index[0] < index[2]));
	assign bigger[2] = ((direction[0] != direction[3]) ^ (index[0] < index[3]));
	assign bigger[3] = ((direction[0] != direction[4]) ^ (index[0] < index[4]));
	assign bigger[4] = ((direction[0] != direction[5]) ^ (index[0] < index[5]));
	assign bigger[5] = ((direction[0] != direction[6]) ^ (index[0] < index[6]));
	assign bigger[6] = ((direction[0] != direction[7]) ^ (index[0] < index[7]));
	assign bigger[7] = ((direction[1] != direction[2]) ^ (index[1] < index[2]));
	assign bigger[8] = ((direction[1] != direction[3]) ^ (index[1] < index[3]));
	assign bigger[9] = ((direction[1] != direction[4]) ^ (index[1] < index[4]));
	assign bigger[10] = ((direction[1] != direction[5]) ^ (index[1] < index[5]));
	assign bigger[11] = ((direction[1] != direction[6]) ^ (index[1] < index[6]));
	assign bigger[12] = ((direction[1] != direction[7]) ^ (index[1] < index[7]));
	assign bigger[13] = ((direction[2] != direction[3]) ^ (index[2] < index[3]));
	assign bigger[14] = ((direction[2] != direction[4]) ^ (index[2] < index[4]));
	assign bigger[15] = ((direction[2] != direction[5]) ^ (index[2] < index[5]));
	assign bigger[16] = ((direction[2] != direction[6]) ^ (index[2] < index[6]));
	assign bigger[17] = ((direction[2] != direction[7]) ^ (index[2] < index[7]));
	assign bigger[18] = ((direction[3] != direction[4]) ^ (index[3] < index[4]));
	assign bigger[19] = ((direction[3] != direction[5]) ^ (index[3] < index[5]));
	assign bigger[20] = ((direction[3] != direction[6]) ^ (index[3] < index[6]));
	assign bigger[21] = ((direction[3] != direction[7]) ^ (index[3] < index[7]));
	assign bigger[22] = ((direction[4] != direction[5]) ^ (index[4] < index[5]));
	assign bigger[23] = ((direction[4] != direction[6]) ^ (index[4] < index[6]));
	assign bigger[24] = ((direction[4] != direction[7]) ^ (index[4] < index[7]));
	assign bigger[25] = ((direction[5] != direction[6]) ^ (index[5] < index[6]));
	assign bigger[26] = ((direction[5] != direction[7]) ^ (index[5] < index[7]));
	assign bigger[27] = ((direction[6] != direction[7]) ^ (index[6] < index[7]));

	assign select[0] = ready[0] & ((~ready[1]) | ready[1] & bigger[0]) & ((~ready[2]) | ready[2] & bigger[1]) & ((~ready[3]) | ready[3] & bigger[2]) & ((~ready[4]) | ready[4] & bigger[3]) & ((~ready[5]) | ready[5] & bigger[4]) & (~ready[6] | ready[6] & bigger[5]) & (~ready[7] | ready[7] & bigger[6]);
	assign select[1] = ready[1] & (~ready[0] | ready[0] & ~bigger[0]) & (~ready[2] | ready[2] & bigger[7]) & (~ready[3] | ready[3] & bigger[8]) & (~ready[4] | ready[4] & bigger[9]) & (~ready[5] | ready[5] & bigger[10]) & (~ready[6] | ready[6] & bigger[11]) & (~ready[7] | ready[7] & bigger[12]);
	assign select[2] = ready[2] & (~ready[0] | ready[0] & ~bigger[1]) & (~ready[1] | ready[1] & ~bigger[7]) & (~ready[3] | ready[3] & bigger[13]) & (~ready[4] | ready[4] & bigger[14]) & (~ready[5] | ready[5] & bigger[15]) & (~ready[6] | ready[6] & bigger[16]) & (~ready[7] | ready[7] & bigger[17]);
	assign select[3] = ready[3] & (~ready[0] | ready[0] & ~bigger[2]) & (~ready[1] | ready[1] & ~bigger[8]) & (~ready[2] | ready[2] & ~bigger[13]) & (~ready[4] | ready[4] & bigger[18]) & (~ready[5] | ready[5] & bigger[19]) & (~ready[6] | ready[6] & bigger[20]) & (~ready[7] | ready[7] & bigger[21]);
	assign select[4] = ready[4] & (~ready[0] | ready[0] & ~bigger[3]) & (~ready[1] | ready[1] & ~bigger[9]) & (~ready[2] | ready[2] & ~bigger[14]) & (~ready[3] | ready[3] & ~bigger[18]) & (~ready[5] | ready[5] & bigger[22]) & (~ready[6] | ready[6] & bigger[23]) & (~ready[7] | ready[7] & bigger[24]);
	assign select[5] = ready[5] & (~ready[0] | ready[0] & ~bigger[4]) & (~ready[1] | ready[1] & ~bigger[10]) & (~ready[2] | ready[2] & ~bigger[15]) & (~ready[3] | ready[3] & ~bigger[19]) & (~ready[4] | ready[4] & ~bigger[22]) & (~ready[6] | ready[6] & bigger[25]) & (~ready[7] | ready[7] & bigger[26]);
	assign select[6] = ready[6] & (~ready[0] | ready[0] & ~bigger[5]) & (~ready[1] | ready[1] & ~bigger[11]) & (~ready[2] | ready[2] & ~bigger[16]) & (~ready[3] | ready[3] & ~bigger[20]) & (~ready[4] | ready[4] & ~bigger[23]) & (~ready[5] | ready[5] & ~bigger[25]) & (~ready[7] | ready[7] & bigger[27]);
	assign select[7] = ready[7] & (~ready[0] | ready[0] & ~bigger[6]) & (~ready[1] | ready[1] & ~bigger[12]) & (~ready[2] | ready[2] & ~bigger[17]) & (~ready[3] | ready[3] & ~bigger[21]) & (~ready[4] | ready[4] & ~bigger[24]) & (~ready[5] | ready[5] & ~bigger[26]) & (~ready[6] | ready[6] & ~bigger[27]);
endmodule

module MemExcResolveUtil(
	input logic _disable,
	input logic [`EXC_CODE_BUS] origin,
	input logic is_write,
	input logic [1: 0] size,
	input logic [1: 0] offset,
	output logic [`EXC_CODE_BUS] out
);
	logic [1: 0] combine_size;
	assign combine_size = {2{_disable}} | size;
	always_comb begin
		case(combine_size)
		2'b10: out = (offset!=2'b00) ? {4'b10, is_write}: origin;
		2'b01: out = (offset == 2'b11 || offset == 2'b01) ? {4'b10, is_write}: origin;
		default: out = origin;
		endcase
	end
endmodule